package com.example.handler.declare;

import com.example.util.CustomNotifier;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.xml.XmlTag;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author Aaron
 * @since 2021/8/30 19:53
 * <p>描述：</p>
 */
public class XmlGoToDeclareHandler extends BaseGoToDeclareHandler {

    private final AnActionEvent anActionEvent;
    private final PsiFile psiFile;
    private final Project project;
    private final Module module;
    private final Editor editor;

    public XmlGoToDeclareHandler(AnActionEvent anActionEvent, PsiFile psiFile) {
        this.anActionEvent = anActionEvent;
        // 当前文件
        this.psiFile = psiFile;

        // 获取当前 Project
        this.project = anActionEvent.getProject();
        Objects.requireNonNull(project, "Can't get the project by the action event.");

        // 当前 Module
        ProjectFileIndex fileIndex = ProjectFileIndex.getInstance(project);
        this.module = fileIndex.getModuleForFile(psiFile.getContainingFile().getVirtualFile());
        Objects.requireNonNull(project, "Can't get the module by the action event.");

        // 获取当前 Editor
        this.editor = CommonDataKeys.EDITOR.getData(anActionEvent.getDataContext());
        Objects.requireNonNull(project, "Can't get the Editor by the action event.");
    }

    @Override
    public void doHandle() {
        super.doHandle();
        // 获取当前位置在 xml 文件中的绝对偏移值
        int currentPositionOffset = this.editor.getCaretModel().getOffset();

        PsiElement element = this.psiFile.findElementAt(currentPositionOffset);
        if (element == null) {
            CustomNotifier.warn(anActionEvent.getProject(), "element is not exists!");
            return;
        }

        // 保存 XML 映射文件中的 namespace 和 id 内容
        Map<String, String> namespaceIdMap = new HashMap<>(3);

        while (element != null) {
            if (!(element instanceof XmlTag)) {
                element = element.getParent();
                continue;
            }

            XmlTag xmlTag = (XmlTag) element;

            // get the value of attribute id that belong to <insert>, <del>, <update> or <select> tag
            if (StringUtils.equalsAny(xmlTag.getName(), "insert", "delete", "update", "select")) {
                String id = xmlTag.getAttributeValue("id");
                namespaceIdMap.put("id", id);
            }

            // get the value of attribute namespace that belong to <mapper> tag
            if (StringUtils.equals(xmlTag.getName(), "mapper")) {
                String namespace = xmlTag.getAttributeValue("namespace");
                namespaceIdMap.put("namespace", namespace);
            }

            element = element.getParent();
        }

        if (!namespaceIdMap.containsKey("namespace") || !namespaceIdMap.containsKey("id")) {
            CustomNotifier.warn(anActionEvent.getProject(), "Retry inside the tag of select, insert etc.");
            return;
        }

        // namespace 在 Mybatis 中的默认形式为 com.example.XxxMapper，这里要找的是 XxxMapper.java 文件
        String[] split = namespaceIdMap.get("namespace").split("\\.");
        String className = split[split.length - 1];
        CustomNotifier.info(anActionEvent.getProject(), "from " + this.psiFile.getName() + " to " + className);

        @NotNull PsiFile[] foundFiles = PsiShortNamesCache.getInstance(project).getFilesByName(String.format("%s.java", className));
        Arrays.stream(foundFiles).forEach(t -> this.doLocate(project, namespaceIdMap.get("id"), t));
    }

}
